﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConfigurationDemo.Config
{
    //基于环境变量的配置扩展方法
    public static class EnvironmentVariablesExtensions
    {
        public static IConfigurationBuilder AddEnvironmentVariables(this IConfigurationBuilder configurationBuilder)
        {
            configurationBuilder.Add(new EnvironmentVariablesConfigurationSource());
            return configurationBuilder;
        }
        public static IConfigurationBuilder AddEnvironmentVariables(
            this IConfigurationBuilder configurationBuilder,
            string? prefix)
        {
            configurationBuilder.Add(new EnvironmentVariablesConfigurationSource { Prefix = prefix });
            return configurationBuilder;
        }

        public static IConfigurationBuilder AddEnvironmentVariables(this IConfigurationBuilder builder, Action<EnvironmentVariablesConfigurationSource>? configureSource)
            => builder.Add(configureSource);
    }

    public class EnvironmentVariablesConfigurationSource : IConfigurationSource
    {
        //命令行前缀
        public string? Prefix { get; set; }
        public IConfigurationProvider Build(IConfigurationBuilder builder)
        {
            return new EnvironmentVariablesConfigurationProvider(Prefix);
        }
    }

    public class EnvironmentVariablesConfigurationProvider : ConfigurationProvider
    {
        private const string MySqlServerPrefix = "MYSQLCONNSTR_";
        private const string SqlAzureServerPrefix = "SQLAZURECONNSTR_";
        private const string SqlServerPrefix = "SQLCONNSTR_";
        private const string CustomConnectionStringPrefix = "CUSTOMCONNSTR_";

        private readonly string _prefix;//命令行前缀
        private readonly string _normalizedPrefix;

        public EnvironmentVariablesConfigurationProvider()
        {
            _prefix = string.Empty;
            _normalizedPrefix = string.Empty;
        }
        public EnvironmentVariablesConfigurationProvider(string? prefix)
        {
            _prefix = prefix ?? string.Empty;
            _normalizedPrefix = Normalize(_prefix);
        }

        public override void Load() =>
            Load(Environment.GetEnvironmentVariables());

        public override string ToString()
        {
            string s = GetType().Name;
            if (!string.IsNullOrEmpty(_prefix))
            {
                s += $" Prefix: '{_prefix}'";
            }
            return s;
        }
        //加载环境变量
        internal void Load(IDictionary envVariables)
        {
            var data = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);

            IDictionaryEnumerator e = envVariables.GetEnumerator();
            try
            {
                while (e.MoveNext())
                {
                    string key = (string)e.Entry.Key;
                    string? value = (string?)e.Entry.Value;

                    if (key.StartsWith(MySqlServerPrefix, StringComparison.OrdinalIgnoreCase))
                    {
                        HandleMatchedConnectionStringPrefix(data, MySqlServerPrefix, "MySql.Data.MySqlClient", key, value);
                    }
                    else if (key.StartsWith(SqlAzureServerPrefix, StringComparison.OrdinalIgnoreCase))
                    {
                        HandleMatchedConnectionStringPrefix(data, SqlAzureServerPrefix, "System.Data.SqlClient", key, value);
                    }
                    else if (key.StartsWith(SqlServerPrefix, StringComparison.OrdinalIgnoreCase))
                    {
                        HandleMatchedConnectionStringPrefix(data, SqlServerPrefix, "System.Data.SqlClient", key, value);
                    }
                    else if (key.StartsWith(CustomConnectionStringPrefix, StringComparison.OrdinalIgnoreCase))
                    {
                        HandleMatchedConnectionStringPrefix(data, CustomConnectionStringPrefix, null, key, value);
                    }
                    else
                    {
                        AddIfNormalizedKeyMatchesPrefix(data, Normalize(key), value);
                    }
                }
            }
            finally
            {
                (e as IDisposable)?.Dispose();
            }

            Data = data;
        }
        //data MYSQLCONNSTR_ MySql.Data.MySqlClient fullKey value
        private void HandleMatchedConnectionStringPrefix(Dictionary<string, string?> data, string connectionStringPrefix, string? provider, string fullKey, string? value)
        {
            //数据库字符串Key
            string normalizedKeyWithoutConnectionStringPrefix = Normalize(fullKey.Substring(connectionStringPrefix.Length));

            // Add the key-value pair for connection string, and optionally provider name
            //ConnectionStrings:DB:MYSQL1 SQL1STR
            AddIfNormalizedKeyMatchesPrefix(data, $"ConnectionStrings:{normalizedKeyWithoutConnectionStringPrefix}", value);
            if (provider != null)//添加某个数据库字符串的数据库类型
            {
                //ConnectionStrings:DB:MYSQL1 MySql.Data.MySqlClient
                AddIfNormalizedKeyMatchesPrefix(data, $"ConnectionStrings:{normalizedKeyWithoutConnectionStringPrefix}_ProviderName", provider);
            }
        }

        //添加普通Key-Value键值对到字典表        
        private void AddIfNormalizedKeyMatchesPrefix(Dictionary<string, string?> data, string normalizedKey, string? value)
        {
            if (normalizedKey.StartsWith(_normalizedPrefix, StringComparison.OrdinalIgnoreCase))
            {
                data[normalizedKey.Substring(_normalizedPrefix.Length)] = value;
            }
        }

        //将下划线替代为:
        private static string Normalize(string key) => key.Replace("__", ConfigurationPath.KeyDelimiter);
    }
}
